package 力扣_算法题综合.高频面试算法;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

public class LFU缓存_460 {
/**
 * 讲的不错, 下面的代码已修改为和LRU类似的代码风格
 * https://leetcode.cn/problems/lfu-cache/solutions/1347315/ceng-ceng-chai-jie-dai-ni-shou-xie-lfu-s-4nku/
 */
}
class LFUCache {
    HashMap<Integer, Integer> cacheMap = new HashMap<>();
    // key 到 freq 的映射
    HashMap<Integer, Integer> freqMap = new HashMap<>();
    // freq 到 key 列表的映射
    HashMap<Integer, LinkedHashSet<Integer>> freqToKeys = new HashMap<>();
    // 记录最小的频次
    int minFreq = 0;
    int capacity = 0;

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }
    public int get(int key) {
        if (!cacheMap.containsKey(key)) {
            return -1;
        }
        // 增加 key 对应的 freq
        increaseFreq(key);
        return cacheMap.get(key);
    }
    public void put(int key, int val) {
        // key已存在
        if (cacheMap.containsKey(key)) {
            cacheMap.put(key, val);
            // key 对应的 freq 加一
            increaseFreq(key);
            return;
        }
        // key不存在,需要插入
        // 容量已满,需要淘汰freq最小的key
        if (this.capacity <= cacheMap.size()) {
            removeMinFreqKey();
        }
        // 插入 key 和 val,对应的 freq 为 1
        cacheMap.put(key, val);
        freqMap.put(key, 1);
        freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
        freqToKeys.get(1).add(key);
        // 插入新 key 后最小的 freq 肯定是 1
        this.minFreq = 1;
    }
    private void removeMinFreqKey() {
        // freq 最小的 key 列表
        LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);
        // 其中最先被插入的那个 key 就是该被淘汰的 key
        int deletedKey = keyList.iterator().next();
        keyList.remove(deletedKey);
        if (keyList.isEmpty()) {
            freqToKeys.remove(this.minFreq);
        }
        cacheMap.remove(deletedKey);
        freqMap.remove(deletedKey);
    }
    private void increaseFreq(int key) {
        int freq = freqMap.get(key);
        freqMap.put(key, freq + 1);
        // 将 key 从 freq 对应的列表中删除
        freqToKeys.get(freq).remove(key);
        // 将 key 加入 freq + 1 对应的列表中
        freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
        freqToKeys.get(freq + 1).add(key);
        // 如果 freq 对应的列表空了,移除这个 freq
        if (freqToKeys.get(freq).isEmpty()) {
            freqToKeys.remove(freq);
            // 如果这个 freq 恰好是 minFreq, 更新 minFreq
            if (freq == this.minFreq) {
                this.minFreq++;
            }
        }
    }
}